﻿#include "mainwindow.h"
#include "./ui_mainwindow.h"

#include "AppConfig/appconfig.h"
#include "userlistwidget.h"
#include "chatwindow.h"

#include <QScreen>
#include "Business/businessviewmodel.h"
#include <UserManager/usermanager.h>
#include "Business/inputhandler.h"

#include <QFileDialog>
#include <QFileInfo>
#include <ThreadPool/threadpool.h>
#include "Business/inputhandler.h"
#include "Business/businessuser.h"
#include "Business/businessgroup.h"

#include <QMessageBox>
#include <Debug/DEBUG.hpp>

#include "avatarselector.h"
#include <QProcess>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    avatarSelector = nullptr;
    // 设置当前的窗口的最大的大小
    QScreen* pdesktop = QGuiApplication::primaryScreen();
    QRect rect1 = pdesktop->availableGeometry();
    setMaximumWidth((int)rect1.width()/3);

    ui->lineEditAccount->setPlaceholderText("输入目标用户的账号");

    QWidget* tabFriend = ui->tabWidget->findChild<QWidget*>("tabFriend");
    if (tabFriend) {
        QVBoxLayout* layout = new QVBoxLayout(tabFriend);
        userList = new UserListWidget(tabFriend);
        friendRequestList = new FriendRequestList(this);
        friendRequestList->setWindowFlag(Qt::Window);
        friendRequestList->hide();

        groupRequestList = new GroupRequestList(this);
        groupRequestList->setWindowFlag(Qt::Window);
        groupRequestList->hide();

        QObject::connect(friendRequestList,
                         &FriendRequestList::updateUserList,
                         this,
                         &MainWindow::on_btnRefreshUserList_clicked);

        BusinessViewModel& view = BusinessViewModel::getInstance();

        QObject::connect(&BusinessViewModel::getInstance(),
                         &BusinessViewModel::userListAddItem,
                         this,
                         &MainWindow::do_userListAddItem);
        QObject::connect(&BusinessViewModel::getInstance(),
                         &BusinessViewModel::requestListAddItem,
                         this,
                         &MainWindow::do_userRequestListAddItem);
        QObject::connect(&BusinessViewModel::getInstance(),
                         &BusinessViewModel::addMessage,
                         this,
                         &MainWindow::addMessageFromUser);
        QObject::connect(&BusinessViewModel::getInstance(),
                         &BusinessViewModel::initUserLoginMessage,
                         this,
                         &MainWindow::initUserLoginMessage);
        QObject::connect(&BusinessViewModel::getInstance(),
                         &BusinessViewModel::SignalUpdateFileTransferInfo,
                         this,
                         &MainWindow::do_updateFileTransferInfo);
        QObject::connect(&BusinessViewModel::getInstance(),
                         &BusinessViewModel::addFileInfoToFileList,
                         this,
                         &MainWindow::do_addFileInfoToFileList);
        QObject::connect(&BusinessViewModel::getInstance(),
                         &BusinessViewModel::signalUpdateStatusbarText,
                         this,
                         &MainWindow::do_updateStatusbarText);
        QObject::connect(&BusinessViewModel::getInstance(),
                         &BusinessViewModel::addGroupItem,
                         this,
                         &MainWindow::do_updateGroupList);
        QObject::connect(&BusinessViewModel::getInstance(),
                         &BusinessViewModel::addGroupMessage,
                         this,
                         &MainWindow::addmessageFromGroup);
        QObject::connect(&BusinessViewModel::getInstance(),
                         &BusinessViewModel::clearGroupRequestList,
                         groupRequestList,
                         &GroupRequestList::clearGroupRequestList);
        QObject::connect(&BusinessViewModel::getInstance(),
                         &BusinessViewModel::addGroupRequestItem,
                         groupRequestList,
                         &GroupRequestList::addAGroupRequest);
        QObject::connect(&BusinessViewModel::getInstance(),
                         &BusinessViewModel::SIGaddMessageFromSelf,
                         this,
                         &MainWindow::addMessageFromSelf);
        QObject::connect(&BusinessViewModel::getInstance(),
                         &BusinessViewModel::SIGupdateStatusbarPermanentText,
                         this,
                         &MainWindow::do_updateStatusbarPermenantText);


        layout->addWidget(userList);
        QWidget* btnGroup = tabFriend->findChild<QWidget*>("btnGroup");
        layout->addWidget(btnGroup);
        tabFriend->setLayout(layout);

        QObject::connect(userList, &UserListWidget::chat, this, &MainWindow::newChatWindow);
        QObject::connect(userList, &UserListWidget::eraseFriend, this, &MainWindow::do_eraseFriend);
        statusBarText = new QLabel(this);
        statusBarPermanentText = new QPushButton(this);
    } else {
        qWarning() << "do not find tabFriend";
    }

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    QJsonObject in, out;
    InputHandler::getInstance()["MainWindow::closeEvent"](in, out);

    emit closeProgram();
    event->accept();
}

void MainWindow::init()
{
    AppConfig& config = AppConfig::getInstance();
    statusBarText->setText("暂无消息");

    statusBarPermanentText -> setText((QString)"当前连接ip：" + config.runtimeValue("IP").c_str());
    statusBarPermanentText -> setIcon(QIcon(":/icon/program/green.svg"));
    statusBarPermanentText -> setFlat(true);
    ui->statusbar->addPermanentWidget(statusBarPermanentText);
    ui->statusbar->addWidget(statusBarText);

    // 初始化数据库
}

std::shared_ptr<ChatWindow> MainWindow::getUserWindow(QString account)
{
    return userChatWindows[account];
}

std::shared_ptr<ChatWindow> MainWindow::getGroupWindow(uint64_t groupID)
{
    return groupChatWindows[groupID];
}

void MainWindow::newChatWindow(QString account, bool show, bool isUser)
{
    qDebug() << "mainWindow new chat window";
    InputHandler& handler = InputHandler::getInstance();
    if (isUser) {
        if (userChatWindows.count(account) != 0) {
            userChatWindows[account]->show();
            return ;
        }
        std::shared_ptr<ChatWindow> window = std::make_shared<ChatWindow>();
        window->setWindow(account, isUser);
        qDebug() << "new chat window: " << account;
        userChatWindows.emplace(account, window);

        // read local chat record and add to the window
        User& user = BusinessUser::getInstance().getTargetUser(account.toStdString());

        // get user id
        int64_t id = user["UserID"];

        // get history message
        QJsonObject in, out;
        in["targetAccount"] = account;
        handler["ChatWindow::getUserHistoryMessage"](in, out);

        // get offline message

        in["TargetUserID"] = (qint64)id;
        handler["MainWindow::newChatWindow"](in, out);

        // show the window
        if (show)
            window->show();

    } else {
        auto& groupInfo = BusinessGroup::getInstance().getTargetGroup(account.toStdString());
        uint64_t groupID = groupInfo["GroupID"];
        if (groupChatWindows.count(groupID)) {
            groupChatWindows[groupID]->show();
            return ;
        }

        std::shared_ptr<ChatWindow> window = std::make_shared<ChatWindow>();
        window->setWindow(account, isUser);
        qDebug() << "new chat window: " << account;
        groupChatWindows.emplace(groupID, window);

        // read local chat record and add to the window
        QJsonObject in, out;
        in["GroupID"] = (qint64)groupID;
        handler["ChatWindow::getGroupHistoryMessage"](in, out);

        // get offline message
        if (show)
            window->show();
    }
}

void MainWindow::addMessageFromUser(int avatar, QString account, QString message, QString time, int messageType)
{
    if (userChatWindows.count(account) == 0) {
        // if window is not exist
        newChatWindow(account, false);
    }
    std::shared_ptr<ChatWindow> ptr = getUserWindow(account);
    if (messageType == 1) {
        ptr->newChat(avatar, account + " : " + message, messageType, time);
    } else {
        ptr->newChat(avatar, message, messageType, time);
    }
}

void MainWindow::addMessageFromSelf(QString targetAccount, QString message, QString time, int messageType)
{
    if (userChatWindows.count(targetAccount) == 0) {
        // if window is not exist
        newChatWindow(targetAccount, false);
    }
    std::shared_ptr<ChatWindow> ptr = getUserWindow(targetAccount);
    User& user = BusinessUser::getInstance().getTargetUser(AppConfig::getInstance().runtimeValue("Account"));
    if (messageType == 1) {
        ptr->newChat(user["Avatar"], (std::string(user["Account"])).c_str() + (QString)" : " + message, messageType, time);
    } else {
        ptr->newChat(user["Avatar"], message, messageType, time);
    }
}




void MainWindow::addmessageFromGroup(int avatar, QString account, uint64_t groupID, QString message,  QString time, int messageType)
{
    if (groupChatWindows.count(groupID) == 0) {
        // if window is not exist
        nlohmann::json groupInfo = BusinessGroup::getInstance().getTargetGroup(groupID);
        QString groupName = std::string(groupInfo["GroupName"]).c_str();
        newChatWindow(groupName, false, false);
    }
    std::shared_ptr<ChatWindow> ptr = getGroupWindow(groupID);
    if (messageType == 1)
        ptr->newChat(avatar, account + ": " + message, messageType, time);
    else
        ptr->newChat(avatar, message, messageType, time);
}

void MainWindow::initUserLoginMessage()
{
    AppConfig& config = AppConfig::getInstance();
    User& user = UserManager::getInstance().getTargetUser(config.runtimeValue("Account"));
    QString imagePath;
    imagePath = ":/icon/avatar/" + QString::number((int)user["Avatar"]) + ".svg";
    QImage ava(imagePath);

    ui->LAavatar->setPixmap(QPixmap::fromImage(ava));
    ui->LAaccount->setText(("Account: " + config.runtimeValue("Account")).c_str());
}

void MainWindow::do_updateFileTransferInfo(QString info)
{
    ui->EditFileInfo->setPlainText(info);
}

void MainWindow::do_addFileInfoToFileList(QString fileInfo)
{
    ui->listWidgetFiles->addItem(fileInfo);
}

void MainWindow::do_updateStatusbarText(QString message)
{
    statusBarText->setText(message);
}

void MainWindow::do_userListAddItem(QString account)
{
    userList->addItem(account);
}

void MainWindow::do_userRequestListAddItem(QString account)
{
    User& user = BusinessUser::getInstance().getTargetUser(account.toStdString());
    DEBUG_INFO(user.dump());
    int avatar = user["Avatar"];
    friendRequestList->addAFriendRequest(avatar, account);
}

void MainWindow::do_eraseFriend(QString account)
{
    QJsonObject in, out;
    in["targetAccount"] = account;
    InputHandler::getInstance()["MainWindow::do_eraseFriend"](in, out);

    on_btnRefreshUserList_clicked();
}

void MainWindow::do_updateGroupList(QString groupName)
{
    ui->listWidgetGroup->addItem(groupName);
}

void MainWindow::do_updateAvatar(int avatar)
{
    QString path = ":/icon/avatar/" + QString::number(avatar) + ".svg";

    QPixmap icon(path);
    ui->LAavatar->setPixmap(icon);
}

void MainWindow::do_updateStatusbarPermenantText(QString message, bool connected)
{
    statusBarPermanentText->setText(message);
    if (connected) {
        statusBarPermanentText->setIcon(QIcon(":/icon/program/green.svg"));
    } else {
        statusBarPermanentText->setIcon(QIcon(":/icon/program/red.svg"));
    }
}

void MainWindow::on_btnUploadFile_clicked()
{
    QString filePath = QFileDialog::getOpenFileName(this,
                                                    "请选择要上传的文件",
                                                    QDir::currentPath(),
                                                    "所有文件(*.*)");


    QFileInfo info(filePath);

    if (info.fileName().isEmpty()) {
        ui->EditFileInfo->setPlainText("无效文件，请重新选择");
        return ;
    }


    QJsonObject in, out;

    in["FileSize"] = info.size();
    in["FileName"] = info.fileName();
    in["FilePath"] = filePath;
    // 1：普通文件，2：聊天图片
    in["FileType"] = 1;

    // use another thread to transmit file
    InputHandler& handler = InputHandler::getInstance();

    ThreadPool& pool = ThreadPool::getInstance();
    pool.commit([&](QJsonObject& in, QJsonObject& out){
        handler["MainWindow::on_btnUploadFile_clicked"](in, out);
    }, in, out);
}


void MainWindow::on_btnDownloadFile_clicked()
{
    auto item = ui->listWidgetFiles->currentItem();
    if (item == nullptr) {
        QMessageBox::information(this,
                                 "注意",
                                 "请选择要下载的文件");
        return ;
    }

    QString fileName = item->text();
    QJsonObject in, out;
    in["FileName"] = fileName;
    in["FileType"] = 1;

    InputHandler::getInstance()["MainWindow::on_btnDownloadFile_clicked"](in, out);
}


void MainWindow::on_btnRefreshFileList_clicked()
{
    QJsonObject in, out;
    ui->listWidgetFiles->clear();
    InputHandler::getInstance()["MainWindow::on_btnRefreshFileList_clicked"](in, out);

    ui->EditFileInfo->setPlainText("请求刷新成功!");
}


void MainWindow::on_btnAddFriend_clicked()
{
    QString targetAccount = ui->lineEditAccount->text();

    QJsonObject in, out;
    in["targetAccount"] = targetAccount;

    InputHandler::getInstance()["MainWindow::on_btnAddFriend_clicked"](in, out);

}


void MainWindow::on_btnFriendRequest_clicked()
{
    friendRequestList->show();
    friendRequestList->activateWindow();
    friendRequestList->setFocus();
}

void MainWindow::on_btnRefreshUserList_clicked()
{
    friendRequestList->clear();
    userList->clear();

    // refresh user list and request list
    QJsonObject in, out;
    InputHandler::getInstance()["MainWindow::on_btnRefreshUserList_clicked"](in, out);

    do_updateStatusbarText("用户列表刷新成功！");
}

void MainWindow::on_btnCreateGroup_clicked()
{
    QString groupName = ui->lineEditGroupName->text();

    if (groupName.isEmpty()) {
        QString title{"消息反馈"};
        QString content{"目标群组名字为空"};
        QMessageBox::information(this, title, content);
        return;
    }


    QJsonObject in, out;
    in["groupName"] = groupName;
    // wait for server response
    InputHandler::getInstance()["MainWindow::on_btnCreateGroup_clicked"](in, out);
    bool ret = out["Status"].toBool();

    if (ret) {
        QString title{"消息反馈"};
        QString content{"群组创建成功，群组名称为：" + groupName};
        int rc = QMessageBox::information(this, title, content);
        if (rc == QMessageBox::Ok) {
            qDebug() << "点击确定";
        }
    } else {
        QString title{"消息反馈"};
        QString content{"群组创建失败，请尝试更换群组名称"};
        int rc = QMessageBox::information(this, title, content);
        if (rc == QMessageBox::Ok) {
            qDebug() << "点击确定";
        }
    }
}


void MainWindow::on_btnRefreshGroupList_clicked()
{
    ui->listWidgetGroup->clear();
    // apply for refresh group list
    QJsonObject in, out;
    InputHandler::getInstance()["MainWindow::on_btnRefreshGroupList_clicked"](in, out);

}


void MainWindow::on_btnJoinGroup_clicked()
{
    QString groupName = ui->lineEditGroupName->text();

    QJsonObject in, out;
    in["groupName"] = groupName;
    InputHandler::getInstance()["MainWindow::on_btnJoinGroup_clicked"](in, out);

    if (out["Status"].toBool()) {
        QString title{"消息反馈"};
        QString content{"已成功发出申请，等待群主同意"};
        int rc = QMessageBox::information(this, title, content);
        if (rc == QMessageBox::Ok) {
            qDebug() << "点击确定";
        }

    } else {
        QString title{"消息反馈"};
        QString content{"未找到目标群组，请检查群组名称是否正确"};
        int rc = QMessageBox::information(this, title, content);
        if (rc == QMessageBox::Ok) {
            qDebug() << "点击确定";
        }
    }
}


void MainWindow::on_listWidgetGroup_itemDoubleClicked(QListWidgetItem *item)
{
    QString QgroupName = item->text();
    newChatWindow(QgroupName, true, false);
}


void MainWindow::on_btnQuitGroup_clicked()
{
    auto item = ui->listWidgetGroup->currentItem();
    if (item == nullptr) {
        QMessageBox::information(this,
                                 "注意",
                                 "请选择要操作的群聊");
        return ;
    }


    // 在某个需要确认的操作的地方
    if (QMessageBox::question(this,
                              "确认操作",
                              "你确定要执行这个操作吗？如果你是群主，退出时群聊会解散!",
                              QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
        // 如果用户点击"Yes"，则执行操作
        QString groupName = item->text();

        QJsonObject in, out;
        in["groupName"] = groupName;

        InputHandler::getInstance()["MainWindow::on_btnQuitGroup_clicked"](in, out);

        on_btnRefreshGroupList_clicked();
    } else {
        // 如果用户点击"No"，则不执行任何操作
        // ...
    }
}

void MainWindow::on_btnGroupManager_clicked()
{
    QJsonObject in, out;
    InputHandler::getInstance()["GroupRequestList::on_btnRefreshRequestList_clicked"](in, out);

    groupRequestList->show();
    groupRequestList->activateWindow();
    groupRequestList->setFocus();
}


void MainWindow::on_btnUpdateAvatar_clicked()
{
    if (avatarSelector == nullptr) {
        avatarSelector = new AvatarSelector(this);
        avatarSelector->setWindowFlag(Qt::Window);

        QObject::connect(avatarSelector, &AvatarSelector::updateAvatar, this, &MainWindow::do_updateAvatar);
    }
    avatarSelector->show();
    groupRequestList->activateWindow();
    groupRequestList->setFocus();
}


void MainWindow::on_pushButton_clicked()
{
    QString strpicPath = (std::filesystem::current_path().string() + "/files").c_str();
    strpicPath.replace("/", "\\");    //win32下替换斜杠
    QProcess process;
    process.startDetached("explorer", QStringList() << QString("/root,") << QString("%1").arg(strpicPath));
}

